
<!doctype html>

<html>
<head>
  <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
  <meta name="theme-color" content="#4F7DC9">
  <meta charset="UTF-8">
  <title>TuyaOS 低功耗门磁设备 demo 指导文档</title>
  <link rel="stylesheet" href="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/codelab-elements.css">
  <link rel="stylesheet" href="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/quickstart.css">
  <style>
    .success {
      color: #1e8e3e;
    }
    .error {
      color: red;
    }
  </style>
</head>
<body>
  <google-codelab-analytics gaid="UA-49880327-14"></google-codelab-analytics>
  <google-codelab codelab-gaid=""
                  id="tuyaos_demo_zg_door_sensor"
                  title="TuyaOS 低功耗门磁设备 demo 指导文档"
                  environment="web"
                  feedback-link="">
    
      <google-codelab-step label="简介" duration="0">
        <p>此文档以开发一个低功耗门磁设备为示例，让开发者了解 TuyaOS Zigbee 开发包的基本原理，并且利用 TuyaOS Zigbee 开发包快速进行开发。最后可以在开发板上实现按键配网、门磁状态上报、电量上报等功能。</p>
<h3 is-upgraded>你能学到什么</h3>
<p>了解 TuyaOS Zigbee 开发包架构以及基础能力；</p>
<p>了解如何开发低功耗子设备；</p>
<p>了解安防设备如何进行注册和数据交互。</p>
<h3 is-upgraded>你需要什么</h3>
<p>windows 操作系统；</p>
<p>USB 转 TTL 工具；</p>
<p>带 ZS3L 模组的一块开发板；</p>
<p>要做完整个工作，我们需要完成以下几个步骤：</p>
<ol type="1">
<li>认识硬件</li>
<li>运行原理（SDK 启动、文件和接口介绍）</li>
<li>修改代码</li>
<li>编译代码</li>
<li>烧写代码</li>
<li>验证功能</li>
</ol>
<p>让我们愉快的开始吧。</p>


      </google-codelab-step>
    
      <google-codelab-step label="硬件准备" duration="0">
        <h3 is-upgraded>认识 Zigbee SoC 主控板（ZS3L）</h3>
<p>涂鸦三明治 Zigbee SoC 主控板（ZS3L）是方便开发者快速实现各种智能硬件产品原型的一款开发板。您可通过涂鸦 Zigbee SoC 主控板（ZS3L），搭配其他功能电路模组或电路板，实现对应的产品功能。</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/c9d1e7c0-fcc1-4001-9235-eb014861b19c.png"></p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/c098267b-37a2-4f67-bb7c-c6227b47861c.png"></p>
<h3 is-upgraded>引脚</h3>
<p>实验中用到的引脚介绍如下，点击查看<a href="https://developer.tuya.com/cn/docs/iot/tuya-sandwich?id=K9lmlvkqwo6rn" target="_blank">Zigbee SoC 主控板（ZS3L）的详细介绍</a>。</p>
<table>
<tr><td colspan="1" rowspan="1"><p>丝印名称</p>
</td><td colspan="1" rowspan="1"><p>芯片引脚编号</p>
</td><td colspan="1" rowspan="1"><p>备注</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p>PB00</p>
</td><td colspan="1" rowspan="1"><p>GPIO_NUM_7</p>
</td><td colspan="1" rowspan="1"><p>按键引脚，初始化高电平，按下为低电平</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p>PA03</p>
</td><td colspan="1" rowspan="1"><p>GPIO_NUM_3</p>
</td><td colspan="1" rowspan="1"><p>门磁状态检测引脚</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p>PA05</p>
</td><td colspan="1" rowspan="1"><p>GPIO_NUM_5</p>
</td><td colspan="1" rowspan="1"><p>串口0 TX 引脚</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p>PA06</p>
</td><td colspan="1" rowspan="1"><p>GPIO_NUM_6</p>
</td><td colspan="1" rowspan="1"><p>串口0 RX 引脚</p>
</td></tr>
</table>
<p>该开发板提供了烧录口(从左往右依次是电源、时钟、数据、复位、地线、地线、TXD、RXD)，可以通过 J-Link 和串口使用涂鸦云模组烧录平台或对应的烧录工具进行烧录。</p>
<p><strong>注意</strong>：ZS3L 是 efr32mg21a020f768im32 芯片平台，需要在 appconfig.json 中 修改chip_id；</p>
<pre><code language="language-json" class="language-json">{
  &#34;firmwareInfo&#34;: {
        &#34;description&#34;: &#34;this is a demon project&#34;,
        &#34;dev_role&#34;:&#34;sleep_end_dev&#34;,
        &#34;image_type&#34;:&#34;0x1602&#34;,
        &#34;manufacture_id&#34;:&#34;0x1002&#34;,
        &#34;model_id&#34;:&#34;TS0203&#34;,
        &#34;pid&#34;: &#34;cz8yd6r2&#34;,
        &#34;manufacture_name&#34;: &#34;_TZ3000_&#34;,
        &#34;module_name&#34;:&#34;ZSU&#34;,
        &#34;chip_id&#34;:&#34;efr32mg21a020f768im32&#34;
  }
}
</code></pre>


      </google-codelab-step>
    
      <google-codelab-step label="SDK 启动流程" duration="0">
        <p>在开始开发前，需要了解 SDK 的初始化流程。启动流程如下图所示。 Tips： 绿底步骤 需要用户关注，进行重写或实现。</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/ecda06d9-0490-4f7b-9cdb-7ba8b9724dc1.png"></p>


      </google-codelab-step>
    
      <google-codelab-step label="文件及函数" duration="0">
        <h3 is-upgraded>部分头文件</h3>
<table>
<tr><td colspan="1" rowspan="1"><p>头文件名称</p>
</td><td colspan="1" rowspan="1"><p>功能</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_tools.h</code></p>
</td><td colspan="1" rowspan="1"><p>Tuya IoT OS 通用工具函数接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tkl_system.h</code></p>
</td><td colspan="1" rowspan="1"><p>提供统一适配系统基础接口，常用 API 有得到系统重启原因，得到系统运行的 ticket 等</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tkl_memory.h</code></p>
</td><td colspan="1" rowspan="1"><p>封装了内存管理接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_error_code.h</code></p>
</td><td colspan="1" rowspan="1"><p>涂鸦对一些错误类型的定义</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_cloud_types.h</code></p>
</td><td colspan="1" rowspan="1"><p>对参数类型的封装。对变量、函数进行类型定义或修饰时应调用这里的函数。</p>
</td></tr>
</table>
<h3 is-upgraded>tuya_sdk_callback.c 文件</h3>
<p><code>tuya_sdk_callback.c</code>和<code>tuya_sdk_callback.h</code> 这两个文件是用户基于 tuyaOS Zigbee 开发包实现应用业务开发的回调接口集合。需要用户根据实际业务场景的需要实现相关回调、虚函数的重写，应用逻辑功能代码的填充等。一些重要的回调函数/虚函数列表如下：</p>
<table>
<tr><td colspan="1" rowspan="1"><p>函数名称</p>
</td><td colspan="1" rowspan="1"><p>函数功能</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_init_first()</code></p>
</td><td colspan="1" rowspan="1"><p>用户侧进行硬件初始化</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_init_second()</code></p>
</td><td colspan="1" rowspan="1"><p>用于 Zigbee 相关初始化、如 Zigbee 设备注册等</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_init_third()</code></p>
</td><td colspan="1" rowspan="1"><p>进入产测前回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_init_last()</code></p>
</td><td colspan="1" rowspan="1"><p>退出产测后回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tuya_main_loop()</code></p>
</td><td colspan="1" rowspan="1"><p>主循环回调接口，谨慎使用，不可阻塞！</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zcl_general_msg_recv_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>ZCL general command 接收回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zcl_specific_msg_recv_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>ZCL specific command 接收回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_nwk_status_changed_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>Zigbee 网络状态改变回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_scene_save_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>add scene/store scene 命令回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_scene_recall_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>recall scene 命令回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_add_group_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>添加群组命令回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_remove_group_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>移除群组命令回调接口</p>
</td></tr>
<tr><td colspan="1" rowspan="1"><p><code>tal_zg_reset_factory_default_callback()</code></p>
</td><td colspan="1" rowspan="1"><p>恢复出厂设置命令回调接口</p>
</td></tr>
</table>


      </google-codelab-step>
    
      <google-codelab-step label="SDK 初始化相关接口" duration="0">
        <h3 is-upgraded>tuya_init_first() 函数介绍</h3>
<p>执行到<code>tuya_init_first()</code>的时候，tuyaOS Zigbee SDK 还没有开始初始化，所有和 Zigbee 有关的资源都不能调用。</p>
<p>一般在<code>tuya_init_first()</code>中进行硬件相关的初始化动作，例如初始化打印串口，业务相关硬件资源，关闭双Dongle测试功能等。</p>
<pre><code language="language-c" class="language-c">/**
 * @brief Generally used for peripheral initialization
 * 
 * @return OPERATE_RET 
 */
OPERATE_RET tuya_init_first(VOID_T)
{
    app_debug_uart_init();
    tal_log_create_manage_and_init(TAL_LOG_LEVEL_TRACE, 128, app_uart_output);

    tal_mf_test_disable_beacon_test();
    TAL_PR_DEBUG(&#34;/*********first init*********/\r\n&#34;);
    return OPRT_OK;
}
</code></pre>
<h3 is-upgraded>tuya_init_second()函数介绍</h3>
<p><code>tuya_init_second()</code>接口需要用户实现和 Zigbee 相关的初始化，包括固件信息、ep 注册、Zigbee 节点配置、入网配置、心跳设置等；</p>
<pre><code language="language-c" class="language-c">/**
 * @brief Generally used for register Zigbee device
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_init_second(VOID_T)
{
    dev_Zigbee_init();
}

/**
 * @brief register Zigbee parameter
 * @return none
 */
VOID_T dev_Zigbee_init(VOID_T)
{
    //register Zigbee endpoint
    tal_zg_endpoint_register(dev_endpoint_desc, GET_ARRAY_LEN(dev_endpoint_desc));

    //Zigbee node configuration
    app_end_device_node_init();

    //Zigbee joining network configuration
    dev_joined_config();

    tal_zg_nwk_recovery_disable(TRUE);
}
</code></pre>
<h3 is-upgraded>tuya_init_third()函数介绍</h3>
<p><code>tuya_init_third()</code>接口在进入产测前会回调，用户自定义实现。</p>
<pre><code language="language-c" class="language-c">OPERATE_RET tuya_init_third(VOID_T)
{
   // TODO:
    return OPRT_OK;
}
</code></pre>
<h3 is-upgraded>tuya_init_last()函数介绍</h3>
<p><code>tuya_init_last()</code>接口在产测结束后会回调，用户自定义实现，此 API 也是进入 while(1) 前最后的回调函数。</p>
<pre><code language="language-c" class="language-c">OPERATE_RET tuya_init_last(VOID_T)
{
    // TODO:
    return OPRT_OK;
}
</code></pre>


      </google-codelab-step>
    
      <google-codelab-step label="SDK 框架函数" duration="0">
        <h3 is-upgraded>tuya_main_loop 函数介绍</h3>
<p>TuyaOS Zigbee 开发包基于前后台软件框架，提供了主循环内的回调接口<code>tuya_main_loop()</code>,由用户依据需求自定义实现相关操作注入系统主循环中。 <strong>注意：</strong><code>tuya_main_loop()</code>主要用于用户侧添加调试、验证性的操作，需<strong>谨慎使用</strong>。此回调接口占用过多时间片会影响整个系统框架的稳定性！！！</p>
<pre><code language="language-c" class="language-c">/**
 * @brief user-defined callback interface in main loop.do not block!!!
 *
 * @return OPERATE_RET
 */
OPERATE_RET tuya_main_loop(VOID_T)
{
    // TODO:
    return OPRT_OK;
}
</code></pre>


      </google-codelab-step>
    
      <google-codelab-step label="Zigbee 网络状态改变回调接口" duration="0">
        <p>当 Zigbee 网络状态发生改变后会回调<code>tal_zg_nwk_status_changed_callback()</code>接口，由应用侧自行定义相应的处理。</p>
<pre><code language="language-c" class="language-c">/**
 * @brief Zigbee network network change callback(user can rewrite this API)
 * 
 * @param[in]   status: network status
 * @return VOID_T
 */
VOID_T tal_zg_nwk_status_changed_callback(TAL_ZG_NWK_STATUS_E status)
{
    switch (status)
    {
        case TAL_ZG_NWK_POWER_ON_LEAVE:
        {
            TAL_PR_TRACE(&#34;power_on_leave---\r\n&#34;);
            break;
        }
        case TAL_ZG_NWK_POWER_ON_ONLINE:
        {
            TAL_PR_TRACE(&#34;power_on_online---\r\n&#34;);
            tal_sw_timer_start(etimer_network_up_delay_event_id, 5000, TAL_TIMER_ONCE);
            break;
        }
        case TAL_ZG_NWK_JOIN_START:
        {
            TAL_PR_TRACE(&#34;nwk_join_start---\r\n&#34;);
#if APP_LED_SUPPORT
            dev_start_join_indicate();
#endif
            break;
        }
        case TAL_ZG_NWK_JOIN_OK:
        {
            TAL_PR_TRACE(&#34;nwk_join_ok---\r\n&#34;);
#if APP_LED_SUPPORT
            dev_join_success_indicate();
#endif
            tal_sw_timer_start(etimer_network_up_delay_event_id, 5000, TAL_TIMER_ONCE);
            app_battery_start();
            break;
        }
        case TAL_ZG_NWK_REJOIN_OK:
        {
            TAL_PR_TRACE(&#34;nwk_rejoin_ok---\r\n&#34;);
            app_battery_start();
            break;
        }
        case TAL_ZG_NWK_JOIN_TIMEOUT:
        {
            TAL_PR_TRACE(&#34;nwk_join_timeout---\r\n&#34;);
            break;
        }
        case TAL_ZG_NWK_LOST:
        {
            TAL_PR_TRACE(&#34;nwk_lost---\r\n&#34;);
            break;
        }
        case TAL_ZG_NWK_REMOTE_LEAVE:
        {
            TAL_PR_TRACE(&#34;nwk_remote_leave---\r\n&#34;);
            tal_zg_join_start(Zigbee_JOIN_TIMEOUT_MS);
            TAL_PR_TRACE(&#34;Zigbee join start %d.\r\n&#34;, Zigbee_JOIN_TIMEOUT_MS);
            break;
        }
        case TAL_ZG_NWK_LOCAL_LEAVE:
        {
            TAL_PR_TRACE(&#34;nwk_local_leave---\r\n&#34;);
            break;
        }
        case TAL_ZG_NWK_MF_TEST_LEAVE:
        {
            TAL_PR_TRACE(&#34;nwk_mf_test_leave---\r\n&#34;);
            break;
        }
        default:
        {
            break;
        }
    }
}
</code></pre>
<p>Zigbee 的网络状态定义如下：</p>
<pre><code language="language-c" class="language-c">/*
 * Zigbee network status
*/
typedef enum {
    TAL_ZG_NWK_IDLE = 0,            ///&lt; inner using
    TAL_ZG_NWK_POWER_ON_LEAVE,      ///&lt; power on and device is not joined network
    TAL_ZG_NWK_POWER_ON_ONLINE,     ///&lt; power on and device is already joined network
    TAL_ZG_NWK_JOIN_START,          ///&lt; start joining network
    TAL_ZG_NWK_JOIN_TIMEOUT,        ///&lt; network joining timeout
    TAL_ZG_NWK_JOIN_OK,             ///&lt; network joined success
    TAL_ZG_NWK_LOST,                ///&lt; network lost, lost parent
    TAL_ZG_NWK_REJOIN_OK,           ///&lt; network rejoin ok
    TAL_ZG_NWK_REMOTE_LEAVE,        ///&lt; remove device by remote device
    TAL_ZG_NWK_LOCAL_LEAVE,         ///&lt; remove device by local
    TAL_ZG_NWK_MF_TEST_LEAVE,       ///&lt; remove device by PC test tools
    TAL_ZG_NWK_ZLL_JOINED,          ///&lt; network joined zll network
    TAL_ZG_NWK_ZLL_LEAVE,           ///&lt; remove device Zll Reset To Factory New
} TAL_ZG_NWK_STATUS_E;

</code></pre>


      </google-codelab-step>
    
      <google-codelab-step label="Zigbee 数据收发接口" duration="0">
        <h2 is-upgraded>数据接收</h2>
<h3 is-upgraded>ZCL general command 接收回调接口</h3>
<p><code>tal_zcl_general_msg_recv_callback()</code>接口处理收到 ZCL 标准定义的 general command 帧。接口定义如下：</p>
<pre><code language="language-c" class="language-c">/**
 * @brief general message receive callback
 *
 * @param msg
 * @return TAL_MSG_RET_E
 */
TAL_MSG_RET_E tal_zcl_general_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
    tal_main_debug(&#34;app gen msg cb: cluster 0x%02x, cmd %d\r\n&#34;, msg-&gt;cluster, msg-&gt;command);

    return ZCL_MSG_RET_SUCCESS;
}
</code></pre>
<p>ZCL 标准 general command 帧定义如下： <img alt="Alt text" src="https://images.tuyacn.com/fe-static/docs/img/859a796f-c895-407d-8188-cc6c3d15d265.png"></p>
<h3 is-upgraded>ZCL specific command 接收回调接口</h3>
<p><code>tal_zcl_general_msg_recv_callback()</code>接口处理收到 ZCL 标准定义的 specific command 帧。接口定义如下：</p>
<pre><code language="language-c" class="language-c">/**
 * @brief specific message receive callback
 * 
 * @param msg 
 * @return TAL_MSG_RET_E 
 */
TAL_MSG_RET_E tal_zcl_specific_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
    TAL_PR_TRACE(&#34;app spec msg cb: cluster 0x%02x, cmd 0x%02x\r\n&#34;, msg-&gt;cluster, msg-&gt;command);

    Zigbee_CMD_E app_cmd_type = Zigbee_CMD_SINGLE;
    if (msg-&gt;mode == ZG_UNICAST_MODE)
    {
        app_cmd_type = Zigbee_CMD_SINGLE;
        TAL_PR_TRACE(&#34;receive single message&#34;);
    }
    else
    {
        app_cmd_type = Zigbee_CMD_GROUP;
        TAL_PR_TRACE(&#34;receive group message&#34;);
    }
    TAL_PR_TRACE(&#34;app command type %d&#34;, app_cmd_type);
    switch (msg-&gt;cluster)
    {
#if IAS_ZONE_SUPPORT
        case CLUSTER_IAS_ZONE_CLUSTER_ID: {
            ias_zone_cluster_server_command_handler(msg-&gt;command, msg-&gt;payload, msg-&gt;length, app_cmd_type);
            break;
        }
#endif
        default:
            break;
    }

    return ZCL_MSG_RET_SUCCESS;
}
</code></pre>
<h2 is-upgraded>数据发送</h2>
<p><code>tal_zg_send_data()</code>接口用于用户侧发送 Zigbee 网络数据，接口原型如下：</p>
<pre><code language="language-c" class="language-c">/**
 * @enum Zigbee data for sending
 */
typedef struct {
    UINT16_T delay_time;                ///&lt; send delay time with ms
    UINT16_T random_time;               ///&lt; send random times with ms
    UINT16_T manu_code;                 ///&lt; manufacturer code
    UINT8_T  manu_spec;                 ///&lt; 1: for enable manufacturer code
    UINT8_T  zcl_id;                    ///&lt; applicaiton sequence number(0x00~0xF0 for user, 0xF0~0xFF for SDK)
    UINT8_T  command_id;                ///&lt; zcl command id, the detail in tuya_Zigbee_commmand.h
    ZG_ZCL_FRAME_TYPE_E frame_type;     ///&lt; zcl frame type
    ZG_ZCL_DATA_DIRECTION_E direction;  ///&lt; data transmission direction
    TAL_SEND_QOS_E qos;                 ///&lt; data service quality
    TAL_ZG_ADDR_T  addr;                ///&lt; Zigbee data address
    union {
        TAL_ZG_DATA_T      zg;
        TAL_PRIVATE_DATA_T private;
    } data;
} TAL_ZG_SEND_DATA_T;

typedef VOID_T (*TAL_SEND_RESULT_CB)(TAL_SEND_ST_E, TAL_ZG_SEND_DATA_T *);

/**
 * @brief receive ack handle
 *
 * @param[in] pdata:    point data to be send
 * @param[in] callback: send result callback
 * @param[in] timeout:  data send timeout
 * @return TRUE: none
 */
VOID_T tal_zg_send_data(TAL_ZG_SEND_DATA_T *pdata, TAL_SEND_RESULT_CB callback, UINT_T timeout);
</code></pre>
<p>其中，<code>callback</code>参数用于注册发送回调，用户可以在此回调接口中获取发送状态信息。</p>


      </google-codelab-step>
    
      <google-codelab-step label="Zigbee 相关操作接口" duration="0">
        <h2 is-upgraded>attribute 操作</h2>
<p><code>tal_attribute_rw.h</code>头文件中提供了 Zigbee 属性的读写接口。接口定义如下：</p>
<pre><code language="language-c" class="language-c">/**
 * @brief write Zigbee attribute
 * NOTE: only for server clusters attributes
 *
 * @param[in]   endpoint: endpoint id
 * @param[in]   cluster:  cluster id
 * @param[in]   attr_id:  attribute id
 * @param[in]   data: point to attribute data to be write
 * @param[in]   type: type of attribute
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tal_zg_write_attribute(UINT8_T endpoint,
                                UINT16_T cluster,
                                UINT16_T attr_id,
                                VOID_T* data,
                                ZG_ATTR_TYPE_E type);

/**
 * @brief read Zigbee attribute
 * NOTE: only for server clusters attributes
 *
 * @param[in]   endpoint: endpoint id
 * @param[in]   cluster:  cluster id
 * @param[in]   attr_id:  attribute id
 * @param[in]   data:     point to attribute data to be read
 * @param[in]   length:   length of attribute data
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tal_zg_read_attribute(UINT8_T endpoint,
                                UINT16_T cluster,
                                UINT16_T attr_id,
                                VOID_T *data,
                                UINT8_T length);

</code></pre>


      </google-codelab-step>
    
      <google-codelab-step label="修改代码" duration="0">
        <h3 is-upgraded>工程目录树</h3>
<pre><code language="language-bash" class="language-bash">sdk_package
├── apps
│   ├── tal_Zigbee_sample
│   │   ├── include
│   │   │   ├── app_battery.h
│   │   │   ├── app_config.h
│   │   │   ├── app_dev_register.h
│   │   │   ├── app_gpio.h
│   │   │   ├── app_ias_zone_attribute.h
│   │   │   ├── app_ias_zone.h
│   │   │   ├── app_key.h
│   │   │   ├── app_led.h
│   │   │   ├── app_mfg.h
│   │   │   ├── attribute-size.h
│   │   │   ├── tuya_hal_gpio.h
│   │   │   ├── tuya_sdk_callback.h
│   │   │   ├── app_common.h
│   │   └── src
│   │   │   ├── tuya_sdk_callback.c # 应用回调接口集文件
│   │   │   ├── app_battery.c
│   │   │   ├── app_config.c
│   │   │   ├── app_dev_register.c
│   │   │   ├── app_gpio.c
│   │   │   ├── app_gpio_callback.c
│   │   │   ├── app_ias_zone_attribute.c
│   │   │   ├── app_ias_zone.c
│   │   │   ├── app_key_callback.c
│   │   │   ├── app_key.c
│   │   │   ├── app_led.c
│   │   │   ├── app_mfg.c
│   │   │   ├── tuya_hal_gpio.c
│   │   │   ├── tuya_sdk_callback.c
│   │   │   ├── app_common.c
│   └── tuya_demo_xx # 用户新建的demo
├── adapter         # 适配层接口文件
├── build           # 适配层接口文件
├── docs            # 相关文档
├── include         # 上层头文件
├── libs            # 静态库文件
├── samples         # 用例集文件
├── scripts         # 脚本集
├── tools           # 工具文件集
├── build_app.bat   # 编译入口脚本
└── findiar.py      # 查找编译器(IAR)路径脚本
</code></pre>
<p>可以根据下面的提示将 PID 信息改为你创建的产品的 PID 信息，也可以不对代码进行任何更改，跳过该步骤直接进入下一步编译生成固件继续操作。</p>
<p>将 <code>/apps/tuyaos_demo_zg_door_sensor</code>目录下的 <code>appconfig.json</code> 中 修改固件信息，注意 dev_role 和 chip_id 需填写正确，否则可能出现运行异常。</p>
<pre><code language="language-c" class="language-c">{
  &#34;firmwareInfo&#34;: {
        &#34;description&#34;: &#34;this is a demon project&#34;,
        &#34;dev_role&#34;:&#34;sleep_end_dev&#34;,
        &#34;image_type&#34;:&#34;0x1602&#34;,
        &#34;manufacture_id&#34;:&#34;0x1002&#34;,
        &#34;model_id&#34;:&#34;TS0203&#34;,
        &#34;pid&#34;: &#34;cz8yd6r2&#34;,
        &#34;manufacture_name&#34;: &#34;_TZ3000_&#34;,
        &#34;module_name&#34;:&#34;ZSU&#34;,
        &#34;chip_id&#34;:&#34;efr32mg21a020f768im32&#34;
  }
}
</code></pre>
<p>配网按键引脚可在 <code>tuya_sdk_callback.h</code> 中的，通过修改 <code>KEY_PIN</code> 进行修改配网按键的引脚，如要使能按键功能，需将 APP_KEY_SUPPORT 宏置 1。</p>
<p>门磁检测引脚可在 <code>tuya_sdk_callback.h</code> 中的，通过修改 <code>GPIO_SENSOR_ALARM_1_PIN</code> 进行修改检测的引脚，如要使能门磁检功能，需将宏 IAS_ZONE_SUPPORT 及 GPIO_SENSOR_ALARM_1_ENABLE 置 1。</p>


      </google-codelab-step>
    
      <google-codelab-step label="烧写流程" duration="0">
        <p>使用云模组烧录授权平台进行烧录授权或者用  [原厂烧录工具] 对编译生成的固件进行烧录。</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/a3eade0b-bbae-4bb7-ab32-2b45f71794f8.jpg"></p>
<h3 is-upgraded>使用云模组烧录工具烧录</h3>
<p>首先设置波特率,点击左上角文件中选中设置,选中波特率为 115200 <img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/81572571-c8b0-4109-91a1-25a004356fb3.png"></p>
<p>点击右侧输入生产凭证,选择生产凭证,点击固件下载,并输入对应的固件 Token,选择烧录授权,点击确定 <img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/67b2c75a-7b4d-484b-a753-d1b19af1dcd9.png"></p>
<p>左侧选择串口端口号,信道选择 11 信道,选择对应的 J-Link 设备，点击运行即可进行烧录授权，假如提示烧录失败，请检查串口及 J-Link 接线是否正确 <img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/e281b457-a94a-4018-add8-d3538301fef8.png"></p>
<h3 is-upgraded>使用原厂烧录工具烧录</h3>
<p>烧录器使用的是 J-Link,烧录工具为芯科下载器,在与开发板连接完成后,从 J-Link Device 下拉框中，选择要使用的烧录器,并点击左上角 adapter <code>connect</code> 按钮,选择完毕后点击 Target <code>connect</code>按钮</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/b153fd13-7a29-4e84-9f5d-f060258044ea.png"></p>
<p>识别芯片，如提示连接失败,尝试插拔 J-Link 并检查接线; 成功识别芯片后,可以从 device info 界面查看芯片的相关信息</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/8bf474c7-92e8-40ba-8b67-47699f7e1dc4.png"></p>
<p>点击左侧 Flash 进入烧录界面,再每次烧录前可以点击 Erase chip 来擦除 flash 中的用户数据;需注意,擦除 flash 后,因为设备的配网信息保存在 flash 中,因此擦除后设备会失去之前的网络配置信息需重新配网。擦除 flash 后点击上方 browse 来选择要烧录的固件,并点击 flash 进行烧录。</p>
<p class="image-container"><img alt="Start-up_flowchart" src="https://images.tuyacn.com/fe-static/docs/img/e4255ab8-5896-44eb-91ee-ee6fa96a091c.png"></p>
<p>烧录完成后通过涂鸦 APP 与设备配网即可实现对设备的上报。</p>


      </google-codelab-step>
    
      <google-codelab-step label="最终效果" duration="0">
        <p>可以通过本地按键 5s 进行配网，配网开始时，设备网络指示灯会闪烁提示开始配网，配网结束后网络指示灯长亮3s后停止闪烁。设备成功配网后，会定时上报电量状态，当触发门磁开关时，会上报门磁状态，可于APP上实时显示。</p>


      </google-codelab-step>
    
  </google-codelab>


  <script src="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/native-shim.js"></script>
  <script src="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/custom-elements.min.js"></script>
  <script src="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/prettify.js"></script>
  <script src="https://images.tuyacn.com/smart/embed/package/vscode/tool-claat/js/codelab-elements.js"></script>
  <script src="//support.google.com/inapp/api.js"></script>

</body>
</html>
